/**
Metamorfose is an interactive ecosystem, which uses computer vision
and sound analysis to define its basic rules.
Copyright (C) 2008  laboratorio (info@laboratorio.us)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

class Ecosystem 
{
  Hashtable amebas;
  Parasite[] parasites;

  /**
   * Class constructor
   */  
  Ecosystem()
  {
    amebas = new Hashtable();
    launchParasites();
  }
  
  /**
   * Defines the entire clicle of the ecosystem
   * basically loading and killing objects as necessary
   */  
  void cicle() { 
    Enumeration iter = amebas.elements();
    while (iter.hasMoreElements()) {
      Ameba element = ((Ameba)iter.nextElement());
      if (!element.isDead()) {
        if (element.reloadComplete()) {
          element.resetAnimation();
        }
        element.render();
        parasiticBehavior(element);
      } else {
        amebas.remove(element);
      }
    }
  }

  /**
   * Gets an amoeba from the acosystem
   * 
   * @param sessionId
   * @return the amoeba, if it exists
   * @see Ameba
   */
  Ameba get(long sessionId) {
    return (Ameba)amebas.get(sessionId);
  }

  /**
   * Adds an amoeba to ecosystem
   */
  void add(long sessionId, float x, float y) { 
    Ameba element = new Ameba(new Vector3D(x, y), 20.0, 0.90);
    amebas.put(sessionId, element);
  }

  /**
   * Removes an amoeba from the ecosystem
   */
  void remove(long sessionId) {
    Ameba element = (Ameba)amebas.get(sessionId);
    amebas.remove(sessionId);
  }

  /**
   * Updates the amoeba's location
   */
  void update(long sessionId, float x, float y, float a) {
    Ameba element = (Ameba)amebas.get(sessionId);
      if (element != null) element.update(new Vector3D(x, y), a);
  } 

  /**
   * Kills an amoeba by its sessionId
   */
  void kill(long sessionId) {
    Ameba element = (Ameba)amebas.get(sessionId);
    element.die();
  }

  /**
   * Kills an amoeba by its instance reference
   * Method override
   */
  void kill(Ameba a) {
    Ameba element = a;
    element.die();
  }

  /**
   * Throws 50 parasites into the ecosystem
   */
  void launchParasites() {
    parasites = new Parasite[50];  
    for (int i = 0; i < parasites.length; i++) {
      Vector3D ac = new Vector3D(0.8f,0.8f);
      Vector3D ve = new Vector3D(0.1f, 0.1f);
      Vector3D lo = new Vector3D(random(width), random(height));
      parasites[i] = new Parasite(ac, ve, lo, random(1, 2));
    }
  }

  /**
   * Tells the parasites which target to follow
   *
   * @param target
   * @see Ameba
   */
  void parasiticBehavior(Ameba target)
  {
    Ameba ameba = target;
    for (int i = 0; i < parasites.length; i++) {
      for (int j = 0; j < parasites.length; j++) {
        if (i != j) {
          Vector3D f = parasites[i].calcGravForce(parasites[j]);
          parasites[i].add_force(f);
        }
        Vector3D af = ameba.calcGravForce(parasites[i]); 
        parasites[i].add_force(af); 
      }
      parasites[i].go();
    }
  }

  /**
   * Do an entire rebirth of the ecosystem
   */
  void reload() { 
    Enumeration iter = amebas.elements();
    while (iter.hasMoreElements()) {
      Ameba element = ((Ameba)iter.nextElement());
      if (!element.isDead() && !element.reloading) {
        element.reload();
      }
    }
  }
}
